<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Mouse Stroke - Options</title>
<link rel="icon" href="icons/icon-16.png"/>
<link rel="stylesheet" href="960.css"/>
<link rel="stylesheet" href="options.css"/>
<script src="essentials.js"></script>
<script src="stroke.js"></script>
<script>
/* the id of the selected stroke command */
var _stroke_id = null;

/* stroke event from stroke.js */
var _event;

/* config object */
var _cfg;

/* when not in setting mode (black screen), respond to strokes like normal
 * webpage */
var _respond = true;

/* port to the background page */
var _port = chrome.extension.connect({name: 'stroke.html-config'});

/* distinguish built-in strokes and custom strokes.
 * custom strokes' IDs are prefixed with CUS_PFX, there are no conflicts
 * as long as built-in strokes' IDs don't use this prefix */
var iscus = function(id) {
	return (new RegExp('^' + $.CUS_PFX)).test(id);
}

/* convert id to a readable label */
var id2label = function(id, type) {
	if (iscus(id))
		return unescape(id.replace(new RegExp('^' + $.CUS_PFX), ''));
	else
		/* go through i18n */
		return _((type ? type : 'stroke') + '_label_' + id.replace(/\-/g, '_'));
}

/* convert label to id, only used by custom strokes */
var label2id = function(label) {
	return $.CUS_PFX + escape(label);
}

/* pack stroke sequence into a space separated string */
var pack = function(seq) {
	return (!!seq && seq.join) ? seq.join(' ').trim() : '';
}

/* generate element IDs based on the custom stroke id */
var cus_label_id = function(id) {
	return id + '-label';
}
var cus_row_id = function(id) {
	return id + '-row';
}

/* synchronize trail style and ui sliders */
var sync_sliders = function(cfg, reverse) {
	var rgb, demo = $.get('trail-demo'), width = $.get('trail_width'),
		r = $.get('trail-color-r'), g = $.get('trail-color-g'),
		b = $.get('trail-color-b');

	if (!reverse) {
		/* right sync, from sliders to UI demo */
		cfg.trail = 'rgb(' + r.value + ',' + g.value + ',' + b.value + ')';
		cfg.trail_width = parseInt(width.value);
		demo.style.backgroundColor = cfg.trail;
		demo.style.height = cfg.trail_width + 'px';
	} else {
		/* reverse sync, from UI demo to sliders */
		rgb = getComputedStyle(demo)
			.getPropertyValue('background-color')
			.match(/^\D+(\d+)\D+(\d+)\D+(\d+)\D.*$/);
		if (rgb) {
			r.value = rgb[1];
			g.value = rgb[2];
			b.value = rgb[3];
		}
		width.value = cfg.trail_width;
	}
}

/* construct the config form */
var construct = function(cfg)
{
	var id, outer, inner, title, box, input, set, unset, cat;

	/* restore options */
	$.get('trigger').value = cfg.trigger;
	$.get('timeout').value = cfg.timeout;
	$.get('minstep').value = cfg.minstep;
	$.get('suppress').checked = !!cfg.suppress;
	$.get('newtab_target').value = cfg.newtab_target;
	$.get('newtab_position').value = cfg.newtab_position;
	$.get('last_tab_close_win').checked = !!cfg.last_tab_close_win;
	$.get('custom_req_ctrlkey').checked = !!cfg.custom_req_ctrlkey;
	$.get('enable_dnd').checked = !!cfg.enable_dnd;
	$.get('enable_animation').checked = !!cfg.enable_animation;

	/* trail settings */
	box = $.get('trail-demo');
	box.style.backgroundColor = cfg.trail;
	box.style.height = cfg.trail_width + 'px';
	sync_sliders(cfg, true);

	box = $.get('search_engine');
	input = $.get('my-search-engine');
	box.value = input.value = cfg.search_engine;
	/* toggle 'my-search-engine' input box */
	input.readOnly = !!box.value;

	/* stroke categories will be flatten for easy referring */
	cfg.strokes = {};

	/* restore built-in stroke settings */
	outer = $.get('built-in-strokes');
	for (id in cfg.categories) {
		title = outer.appendChild($.create('p', {
			className: 'title',
			textContent: id2label(id, 'category')
		}));
		inner = outer.appendChild($.create('div', {
			className: 'fold-group'
		}));

		/* strokes */
		cat = cfg.categories[id];
		for (id in cat) {
			box = inner.appendChild($.create('div', {
				className: 'row clear'
			}));
			box.appendChild($.create('p', {
				className: 'label grid_4 alpha',
				textContent: id2label(id)
			}));
			box = box.appendChild($.create('p', {
				className: 'field grid_8 omega'
			}));
			/* stroke field */
			input = $.create('input', {
				id: id, type: 'text', disabled: true,
				className: 'stroke-field', value: pack(cat[id])
			});
			/* set button */
			set = $.create('button', {
				className: 'set-stroke-btn', 'for': id,
				textContent: _('caption_set')
			});
			set.addEventListener('click', set_stroke, false);
			/* unset button */
			unset = $.create('button', {
				className: 'unset-stroke-btn', 'for': id,
				textContent: _('caption_unset')
			});
			unset.addEventListener('click', unset_stroke, false);

			box.appendChild(input);
			box.appendChild(set);
			box.appendChild(unset);

			/* flat categories, all operations on cfg.strokes
			 * should done by reference, so that changes can be
			 * reflected on their counterparts in cfg.categories */
			cfg.strokes[id] = cat[id];
		}

		/* built-in strokes are too many, make them foldable */
		title.addEventListener('click', function(ev) {
			var title = ev.target;
			if (!title.folded) $.slide_up(title.nextElementSibling);
			else $.slide_down(title.nextElementSibling);
			title.folded = !title.folded;
		}, false);
		/* by default fold all but the first category */
		if (title.previousElementSibling) {
			$.slide_up(title.nextElementSibling);
			title.folded = true;
		}
	}

	/* rocker and wheel strokes */
	pxy_construct(cfg);

	/* restore custom stroke settings */
	box = $.get('custom-strokes');
	for (id in cfg.customs) {
		box.appendChild(cus_construct(id));
	}

	/* bind restore/save button listener */
	$.get('top-restore-btn').addEventListener('click', restore_default, false);
	$.get('bot-restore-btn').addEventListener('click', restore_default, false);
	$.get('top-save-btn').addEventListener('click', harvest, false);
	$.get('bot-save-btn').addEventListener('click', harvest, false);
}

var pxy_construct = function(cfg) {
	var proxies = ['rockers-L', 'rockers-R',
		'wheels-U', 'wheels-D', 'wheels-L', 'wheels-R',
		'drags-U', 'drags-D', 'drags-L', 'drags-R'],
		i, id, sel, grp, types, main, sub, cat;
	for (i = 0; i < proxies.length; ++i) {
		sel = $.get(proxies[i]);
		types = sel.id.split('-');
		main = types[0], sub = types[1];

		/* these elements will be rebuilt when saving */
		sel.innerHTML = '';

		sel.appendChild($.create('option', {
			value: '', textContent: _('caption_none')
		}));

		if (main == 'drags') {
			/* for drags, only link type strokes are supported */
			for (id in cfg.categories.link) {
				sel.appendChild($.create('option', {
					value: id, textContent: id2label(id)
				}));
			}
		} else {
			/* rockers and wheels support them all */
			/* fill in built-in strokes */
			for (id in cfg.categories) {
				sel.appendChild(grp = $.create('optgroup', {
					label: id2label(id, 'category')
				}));
				cat = cfg.categories[id];
				for (id in cat) {
					grp.appendChild($.create('option', {
						value: id,
						textContent: id2label(id)
					}));
				}
			}

			/* fill in custom strokes */
			sel.appendChild(grp = $.create('optgroup', {
				label: _('category_label_custom_strokes')
			}));
			for (id in cfg.customs) {
				grp.appendChild($.create('option', {
					value: id, textContent: id2label(id)
				}));
			}
		}

		sel.value = cfg[main][sub];
		sel.addEventListener('change', function(ev) {
			var ids = ev.target.id.split('-');
			_cfg[ids[0]][ids[1]] = ev.target.value;
		}, false);
	}
	if (!$.WIN) {
		$.hide('windows-exclusive');
	}
}

/* create UI for custom strokes */
var cus_construct = function(id) {
	var row, box, input, set, unset, remove, stroke = _cfg.customs[id];

	row = $.create('div', { id: cus_row_id(id), className: 'row clear' });
	/* label text */
	row.appendChild($.create('p', {
		id: cus_label_id(id), className: 'label grid_4 alpha',
		textContent: id2label(id)
	}));
	box = row.appendChild($.create('p', {
		className: 'field grid_8 omega'
	}));
	/* stroke field */
	input = $.create('input', {
		id: id, type: 'text', disabled: true,
		className: 'stroke-field', value: pack(stroke)
	});
	/* set button */
	set = $.create('button', {
		className: 'set-stroke-btn', 'for': id,
		textContent: _('caption_set')
	});
	set.addEventListener('click', set_stroke, false);
	/* unset button */
	unset = $.create('button', {
		className: 'unset-stroke-btn', 'for': id,
		textContent: _('caption_unset')
	});
	unset.addEventListener('click', unset_stroke, false);
	/* remove button */
	remove = $.create('button', {
		className: 'remove-stroke-btn', 'for': id,
		textContent: _('caption_remove')
	});
	remove.addEventListener('click', remove_stroke, false);

	box.appendChild(input);
	box.appendChild(set);
	box.appendChild(unset);
	box.appendChild(remove);

	return row;
}

/* save settings */
var harvest = function()
{
	var i, el, customs, se;

	_cfg.trigger = parseInt($.get('trigger').value);
	_cfg.timeout = parseInt($.get('timeout').value);
	_cfg.minstep = parseInt($.get('minstep').value);
	_cfg.suppress = $.get('suppress').checked;
	_cfg.newtab_target = $.get('newtab_target').value;
	_cfg.newtab_position = $.get('newtab_position').value;
	_cfg.blacklist = $.get('blacklist-ta').value;
	_cfg.last_tab_close_win = $.get('last_tab_close_win').checked;
	_cfg.custom_req_ctrlkey = $.get('custom_req_ctrlkey').checked;
	_cfg.enable_dnd = $.get('enable_dnd').checked;
	_cfg.enable_animation = $.get('enable_animation').checked;

	/* search should be set */
	se = $.get('search_engine').value || $.get('my-search-engine').value;
	if (!se || !/^https?:\/\/.+/i.test(se)) {
		$.prompt(_('prompt_invalid_search_engine_url'));
		return;
	}
	_cfg.search_engine = se;

	/* if the label of a custom stroke was changed, its internal
	 * order within _cfg.customs will also change, so we need to re-sort
	 * _cfg.customs by elements order here */
	for (el = $.get('custom-strokes').getElementsByClassName('stroke-field'),
		i = 0, customs = {};
		i < el.length;
		customs[el[i].id] = _cfg.customs[el[i++].id]);
	_cfg.customs = customs;

	/* rebuild affected UI elements */
	pxy_construct(_cfg);

	/* save locally */
	_port.postMessage({ type: 'save', data: _cfg });
	$.prompt(_('prompt_save_complete'), 2);
}

/* restore default settings */
var restore_default = function()
{
	if (!confirm(_('prompt_reset_settings')))
		return;

	_port.postMessage({
		type: 'save',
		data: { customs: _cfg.customs, scripts: _cfg.scripts }
	});
	location.reload(true);
}

/* event handler for setting stroke */
var set_stroke = function(e)
{
	var is_custom, stroke, custom;

	/* set the command id, so the stroke listener knows which stroke
	 * should be set */
	_stroke_id = e.target['for'];
	_respond = false;
	is_custom = iscus(_stroke_id);
	stroke = is_custom ? _cfg.customs[_stroke_id] : _cfg.strokes[_stroke_id];

	if (is_custom) {
		custom = _cfg.scripts[_stroke_id];
		$.get('custom-label').value = id2label(_stroke_id);
		$.get('custom-script').value = custom && custom.script || '';
		$.get('custom-runs-in').value = custom && custom.frame || 'all';
		$.show('custom-content');
	}
	/* display the overlay, waiting for input */
	$.get('which-stroke').textContent = id2label(_stroke_id);
	$.get('old-stroke').textContent = pack(stroke);
	$.get('new-stroke').textContent = '';
	$.show('overlay-stroke');
	$.hide('overlay-backup');
	$.hide('overlay-blacklist');
	$.show('overlay');
}

/* event handler for unsetting stroke */
var unset_stroke = function(e) {
	var k = e.target['for'],
		s = iscus(k) ? _cfg.customs[k] : _cfg.strokes[k];
	/* unset the stroke */
	$.get(k).value = '';
	/* empty the stroke array */
	s.splice(0, s.length);
}

/* event handler for remove custom stroke */
var remove_stroke = function(e) {
	var k = e.target['for'];
	if (confirm(_('prompt_remove_custom_stroke', id2label(k)))) {
		$.erase($.get(cus_row_id(k)));
		delete _cfg.customs[k];
		delete _cfg.scripts[k];
	}
}

/* event handler for add new custom stroke */
var add_stroke = function(e, one_click) {
	var id, i = 1, label = 'New Custom Stroke ';

	if (!!one_click && !!one_click.script) {
		if (!!one_click.title) label = one_click.title;
		/* don't change title unless the title has been used */
		id = label2id(label);
		while (!!_cfg.customs[id]) id = label2id(label + i++);
		/* set properties */
		_cfg.scripts[id] = {
			frame: one_click.frame || '',
			script: one_click.script || ''
		}
	} else {
		do { id = label2id(label + i++) }
		while (!!_cfg.customs[id]);
	}

	/* push a special new stroke to customs */
	_cfg.customs[id] = [];
	_cfg.customs[id].neo = true;
	/* tell a lie */
	e.target['for'] = id;
	set_stroke(e);
}

/* event handler for the confirm button */
var confirm_change = function(e) {
	var k, tr, label, script, newstk, frame, is_custom = iscus(_stroke_id),
		bucket = is_custom ? _cfg.customs : _cfg.strokes,
		stroke = bucket[_stroke_id],
		id = _stroke_id;

	/* label and script */
	if (is_custom) {
		label = $.get('custom-label').value.trim();
		script = $.get('custom-script').value;
		frame = $.get('custom-runs-in').value;
		if (!label || !script.trim()) {
			$.prompt(_('prompt_label_and_script_are_empty'), 4);
			return;
		}
		/*if (!evaluate(script)) return;*/

		/* id does not equal to _stroke_id if label is changed */
		id = label2id(label);
		/* notify conflicts */
		if (_stroke_id != id && !!bucket[id] && !confirm(_('prompt_overwrite_custom_stroke_label', label)))
			return;
	}

	/* update stroke setting */
	if (!!_event && !!_event.stroke) {
		newstk = pack(_event.stroke);
		/* check duplicates */
		for (k in bucket) {
			if (id != k && newstk == pack(bucket[k])) {
				if (confirm(_('prompt_overwrite_stroke_sequence', [newstk, id2label(k)]))) {
					/* clear conflicted settings */
					$.get(k).value = '';
					bucket[k].splice(0, bucket[k].length);
					break;
				} else {
					return;
				}
			}
		}
		/* operate on the array reference, replace array elements
		 * with elements of _event.stroke */
		stroke.splice.apply(stroke, [0, stroke.length].concat(_event.stroke));
	}

	/* handle label change, update page elements */
	if (_stroke_id != id || stroke.neo) {
		/* a new stroke, or label changed */
		bucket[id] = stroke;
		tr = $.get(cus_row_id(_stroke_id));
		/* insert a new row if the user is adding a new stroke,
		 * or editing the label of an existing stroke */
		if (!$.get(cus_row_id(id)))
			$.get('custom-strokes').insertBefore(cus_construct(id), tr);
		/* remove the old row label is changed */
		if (_stroke_id != id) {
			delete bucket[_stroke_id];
			delete _cfg.scripts[_stroke_id];
			$.erase(tr);
		}
		/* from now on _stroke_id is replaced by new id, later
		 * references to _stroke_id should be pointed to the new id */
		_stroke_id = id;
	}
	if (!!newstk || stroke.neo) $.get(id).value = newstk || pack(stroke);

	if (is_custom) _cfg.scripts[id] = { frame: frame, script: script };
	if (stroke.neo) delete stroke.neo;

	cancel_change(e);
}

/* event handler for the cancel button */
var cancel_change = function(e) {
	/* cancel setting stroke */
	if (!!_cfg.customs[_stroke_id] && _cfg.customs[_stroke_id].neo) {
		/* a new stroke is cancelled */
		delete _cfg.customs[_stroke_id];
		delete _cfg.scripts[_stroke_id];
	}
	$.hide('overlay');
	$.hide('custom-content');
	_stroke_id = null;
	_event = null;
	_respond = true;
}

/* backup config */
var backup_config = function(e) {
	var ta = $.get('backup-ta');
	ta.value = JSON.stringify(_cfg);
	ta.focus();
	ta.select();
}

/* restore config */
var restore_config = function(e) {
	var cfg;
	try {
		cfg = JSON.parse($.get('backup-ta').value)
		_port.postMessage({ type: 'save', data: cfg });
		$.prompt(_('prompt_restore_complete'), null, function() {
			location.reload(true);
		});
	} catch (e) {
		$.prompt(_('prompt_backup_settings_currupted'));
		return;
	}
}

/* save blacklist settings */
var confirm_blacklist = function(e) {
	_cfg.blacklist = $.get('blacklist-ta').value;
	_port.postMessage({ type: 'save', data: _cfg });
	$.prompt(_('prompt_save_blacklist_complete'), 2);
}

/* evaluate scripts of custom strokes */
var evaluate = function(script) {
	var ex, msg, line, sbox = $.get('sandbox').contentWindow;
	if (true !== (ex = sbox.sandbox.call({}, {}, script))) {
		/* extract compiler messages */
		ex = ex.stack.split("\n");
		line = ex[1].replace(/.+actions\.js:\d+:(\d+).+$/, '$1');
		msg = "The compiler reported a script error.\n\n";
		msg += ex[0]/* + "\nAt line: " + (line ? line : '<unknown>')*/;
		msg += "\n\nProceed with errors?";

		return confirm(msg);
	}
	return true;
}

/* one click installation handler */
var one_click = function(data) {
	var e = document.createEvent('MouseEvent');
	e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
	document.createElement('button').dispatchEvent(e);

	add_stroke(e, data);
}

/* all procedures which should be called after _cfg is ready */
var cfg_ready = function() {
}

chrome.extension.onRequest.addListener(function(msg, sender, send_resp) {
	var resp = {}

	/* stroke.js will fire a pull-config command to stroke.html at
	 * start up, we listen to the response too */
	if (!_cfg && 'update-config' == msg.type) {
		/* apply only once */
		construct(_cfg = msg.data);
		cfg_ready();
	} else if ('one-click-install' == msg.type) {
		try {
			one_click(msg.data);
		} catch (ex) {
			console.error(ex.stack);
			$.prompt(ex, 5);
		}
	} else if ('accept-stroke' == msg.type) {
		/* tell stroke.html whether we are responding to strokes */
		if (!(resp = _respond) &&
			/* in setting mode */
			'stroke' == msg.data.type && !!_stroke_id &&
			!!_cfg[iscus(_stroke_id) ? 'customs' : 'strokes'][_stroke_id]) {

			/* valid _stroke_id */
			_event = msg.data;
			$.get('new-stroke').textContent = pack(_event.stroke);
		}
	} else {
		return;
	}
	send_resp(resp);
});

window.addEventListener('load', function() {
	var sbox;

	$.get('confirm-btn').addEventListener('click', confirm_change, false);
	$.get('cancel-btn').addEventListener('click', cancel_change, false);
	$.get('add-custom-btn').addEventListener('click', add_stroke, false);
	$.get('backup-config-btn').addEventListener('click', backup_config, false);
	$.get('restore-config-btn').addEventListener('click', restore_config, false);
	$.get('blacklist-confirm-btn').addEventListener('click', confirm_blacklist, false);
	$.get('open-backup-ui').addEventListener('click', function() {
		/* show UI for backup/restore settings */
		$.get('backup-ta').value = '';
		$.hide('overlay-stroke');
		$.hide('overlay-blacklist');
		$.show('overlay-backup');
		$.show('overlay');
	}, false);
	$.get('close-backup-ui').addEventListener('click', function() {
		$.hide('overlay');
	}, false);
	$.get('open-blacklist-ui').addEventListener('click', function() {
		$.get('blacklist-ta').value = _cfg.blacklist;
		$.hide('overlay-stroke');
		$.hide('overlay-backup');
		$.show('overlay-blacklist');
		$.show('overlay');
	}, false);
	$.get('close-blacklist-ui').addEventListener('click', function() {
		$.hide('overlay');
	}, false);
	$.get('show-advanced-options').addEventListener('click', function(e) {
		$.slide_up(e.target.parentNode, function() { $.erase(e.target.parentNode) });
		$.slide_down('advanced-options');
	}, false);
	$.get('search_engine').addEventListener('change', function(ev) {
		var el = $.get('my-search-engine');
		el.value = ev.target.value || 'http://';
		el.readOnly = !!ev.target.value;
		el.focus();
	}, false);
	$.get('edit-trail-style').addEventListener('click', function() {
		$.fade_in('trail-style');
	}, false);
	$.get('hide-trail-style').addEventListener('click', function() {
		$.fade_out('trail-style');
	}, false);
	$.get('trail_width').addEventListener('change', function(e) {
		sync_sliders(_cfg, false);
	}, false);
	$.get('trail-color-r').addEventListener('change', function() {
		sync_sliders(_cfg, false);
	}, false);
	$.get('trail-color-g').addEventListener('change', function() {
		sync_sliders(_cfg, false);
	}, false);
	$.get('trail-color-b').addEventListener('change', function() {
		sync_sliders(_cfg, false);
	}, false);

	/* inline localization */
	$.i18n();
	/* hide advanced options */
	$.slide_up('advanced-options');

	/* prepare the sandbox for evaluating user script
	sbox = $.get('sandbox').contentWindow;
	sbox.document.head.appendChild($.create('script', {
		type: 'text/javascript', src: 'actions.js'
	}));
	sbox.parent = sbox;
	sbox.alert = sbox.confirm = function() {}*/
});
</script>
</head>
<body class="container_24">

<div id="overlay" class="overlay hidden">
 <div id="overlay-stroke" class="overlay-stroke">
  <h1 id="which-stroke"></h1>
  <p><span class="i18n" msg="caption_previous_stroke">Previous</span><br/>[ <span id="old-stroke" class="old-stroke"></span> ]</p>
  <p><span class="i18n" msg="caption_current_stroke">Current</span><br/>[ <span id="new-stroke" class="new-stroke"></span> ]</p>
  <div id="custom-content" class="custom-content hidden">
   <p><em class="i18n" msg="caption_label">Label</em> *<br/>
    <input id="custom-label" class="custom-label" type="text" maxlength="64"/>
   </p>
   <p>
    <em class="i18n" msg="option_label_custom_stroke_runs_in">Runs in</em>
    <select id="custom-runs-in">
     <option value="all" class="i18n" msg="option_value_all_frames">All frames</option>
     <option value="top" class="i18n" msg="option_value_top_frame">Top frame</option>
     <option value="target" class="i18n" msg="option_value_target_frame">Target frame</option>
    </select>
    (<a href="http://ganq.net/mouse-stroke/page/custom-stroke-howto#runs-in-which-frame">?</a>)
   </p>
   <p><em class="i18n" msg="caption_script">Script</em> *
    (New in 1.9.5: <a href="http://ganq.net/mouse-stroke/page/custom-stroke-howto#built-in-stroke-handlers"><strong>Call built-in stroke handlers</strong></a>)
    <br/>
    <textarea id="custom-script" class="custom-script" spellcheck="false"></textarea>
   </p>
  </div>
  <p>
   <button id="confirm-btn" class="i18n" msg="caption_confirm">Confirm</button>
   <button id="cancel-btn" class="i18n" msg="caption_cancel">Cancel</button>
  </p>
 </div>

 <div id="overlay-backup" class="overlay-backup">
  <h1 class="i18n" msg="caption_backup_or_restore_settings">Backup / Restore Settings</h1>
  <div class="backup-form">
    <ol id="backup-prompt" class="backup-prompt i18n" msg="text_backup_and_restore_settings_description">
     <li>To backup settings, hit the "Backup" button then <strong>copy the text
      content to a safe place</strong>. Hit the button alone will not save
      your settings.
     </li>
     <li>To restore settings, paste previously saved content in the text area
      then hit the "Restore" button. Your backup data will be merged with the
      default settings to avoid incompatibility or data corruption.
     </li>
    </ol>
   <p>
    <textarea id="backup-ta" class="backup-ta" spellcheck="false"></textarea>
   </p>
  </div>
  <p>
   <button id="backup-config-btn" class="i18n" msg="caption_backup">Backup</button>
   <button id="restore-config-btn" class="i18n" msg="caption_restore">Restore</button>
   <button id="close-backup-ui" class="i18n" msg="caption_close">Close</button>
  </p>
 </div>

 <div id="overlay-blacklist" class="overlay-blacklist">
  <h1 class="i18n" msg="caption_blacklist">Blacklist</h1>
  <div class="blacklist-form">
   <p class="i18n" msg="text_blacklist_description">
    Mouse Stroke will be disabled for websites in the blacklist.
    Please add one URL per line.<br/>
    Wildcards and regular expressions are <strong>NOT</strong> supported.<br/>
    You should be as specific as possible because simple entries, i.e. <code>shoes</code>,
    will blacklist all websites that has 'shoes' in their URL.
   </p>
   <p>
    <textarea id="blacklist-ta" class="blacklist-ta" spellcheck="false"></textarea>
   </p>
  </div>
  <p>
   <button id="blacklist-confirm-btn" class="i18n" msg="caption_confirm">Confirm</button>
   <button id="close-blacklist-ui" class="i18n" msg="caption_close">Close</button>
  </p>
 </div>
</div>

<!--iframe id="sandbox" class="hidden"></iframe-->

<div id="header" class="header grid_24">
 <h1 class="i18n" msg="caption_mouse_stroke_options">Mouse Stroke Options</h1>
</div>

<div class="submit grid_24">
 <button id="top-restore-btn" class="i18n" msg="caption_restore_default">Restore to default</button>
 <button id="top-save-btn" class="i18n" msg="caption_save">Save</button>
</div>

<div id="options" class="options grid_24">
 <p class="title"><span class="i18n" msg="category_label_options">Options</span>
  <span class="float-right">
   <a id="open-backup-ui" href="javascript:void(0)" class="open-backup-ui i18n" msg="caption_backup_or_restore_settings">
    Backup or restore settings
   </a>
   |
   <a id="open-blacklist-ui" href="javascript:void(0)" class="open-blacklist-ui i18n" msg="caption_blacklist">
    Blacklist
   </a>
  </span>
 </p>
 <div class="fold-group">
  <div class="row clear">
   <p class="label grid_6 alpha i18n" msg="option_label_stroke_trigger">Stroke Trigger</p>
   <p class="field grid_10">
    <select id="trigger">
     <!--option value="0" class="i18n" msg="option_value_left_mouse_button">Left Mouse Button</option-->
     <option value="1" class="i18n" msg="option_value_middle_mouse_button">Middle Mouse Button (Linux and Mac)</option>
     <option value="2" class="i18n" msg="option_value_right_mouse_button">Right Mouse Button (Windows)</option>
    </select>
   </p>

   <p class="label grid_8 omega">
    <input id="suppress" type="checkbox"/>
    <label for="suppress" class="i18n" msg="option_label_alt_key_suppresses_strokes">Alt key suppresses strokes</label>
   </p>
  </div>

  <div class="row clear">
   <p class="label grid_6 alpha i18n" msg="option_label_draw_trails">Draw Trails</p>
   <div class="field grid_10">
    <div id="trail-demo" class="trail-demo"></div>
    <div>
     <button id="edit-trail-style" class="i18n" msg="caption_edit_trail_style">Edit trail style</button>
    </div>
   </div>

   <p class="label grid_8 omega">
    <input id="last_tab_close_win" type="checkbox"/>
    <label for="last_tab_close_win" class="i18n" msg="option_label_close_window_with_the_last_tab">Close window with the last tab</label>
   </p>
  </div>

  <div id="trail-style" class="push_6 hidden trail-style">
   <span class="i18n" msg="option_label_trail_color">Trail Color</span><br/>
   <input id="trail-color-r" type="range" min="0" max="255" step="1"/><br/>
   <input id="trail-color-g" type="range" min="0" max="255" step="1"/><br/>
   <input id="trail-color-b" type="range" min="0" max="255" step="1"/><br/>
   <span class="i18n" msg="option_label_trail_width">Trail Width</span><br/>
   <input id="trail_width" type="range" min="0" max="9" step="1"/><br/>
   <button id="hide-trail-style" class="hide-trail-style float-right i18n" msg="caption_confirm">Confirm</button>
  </div>

  <div class="row clear">
   <p class="label grid_6 alpha i18n" msg="option_label_page_open_as_new_tab">When Open New Tabs, Open</p>
   <p class="field grid_10">
    <select id="newtab_target">
     <option value="" class="i18n" msg="option_value_my_homepage">My homepage</option>
     <option value="about:blank" class="i18n" msg="option_value_the_blank_page">The blank page</option>
     <option value="chrome://newtab/" class="i18n" msg="option_value_chrome_newtab_page">Chrome's new tab page</option>
    </select>
   </p>

   <p class="label grid_8 omega">
    <input id="custom_req_ctrlkey" type="checkbox"/>
    <label for="custom_req_ctrlkey" class="i18n" msg="option_label_hold_ctrl_key_to_fire_custom_strokes">Hold Ctrl key to fire Custom Strokes</label>
    (<a href="http://ganq.net/mouse-stroke/page/mouse-stroke-faqs#ctrl-button-vs-no-ctrl-button">?</a>)
   </p>
  </div>

  <div class="row clear">
   <p class="label grid_6 alpha i18n" msg="option_label_new_tab_open_at">When Open New Tabs, Open</p>
   <p class="field grid_10">
    <select id="newtab_position">
     <option value="+0" class="i18n" msg="option_value_at_left_of_current_tab">At the left of the current tab</option>
     <option value="+1" class="i18n" msg="option_value_at_right_of_current_tab">At the right of the current tab</option>
     <option value="*0" class="i18n" msg="option_value_as_first_tab">As the first tab</option>
     <option value="/0" class="i18n" msg="option_value_as_last_tab">As the last tab</option>
    </select>
   </p>

   <p class="label grid_8 omega">
    <input id="enable_dnd" type="checkbox"/>
    <label for="enable_dnd" class="i18n" msg="option_label_enable_dnd_strokes">Enable Drag'n'Drop Strokes</label>
   </p>
  </div>

  <div class="row clear">
   <p class="label grid_6 alpha">
    <span class="i18n" msg="option_label_prefferred_search_engine">Preferred Search Engine</span>
    (<a href="http://ganq.net/mouse-stroke/page/mouse-stroke-faqs#how-to-add-search-engine-plugin">?</a>)
   </p>
   <p class="field grid_18 omega">
    <select id="search_engine">
     <option value="" class="i18n" msg="option_value_other_search_engine">Other</option>
     <option value="http://www.google.com/search?q=">Google</option>
     <option value="http://www.bing.com/search?q=">Bing</option>
     <option value="http://search.yahoo.com/search?p=">Yahoo!</option>
     <option value="http://www.ask.com/web?q=">Ask.com</option>
     <option value="http://search.aol.com/aol/search?q=">AOL Search</option>
    </select>
    <input id="my-search-engine" type="text" size="80"/>
   </p>
  </div>

  <div class="row clear">
   <button id="show-advanced-options" class="i18n" msg="caption_show_advanced_options">Show advanced options</button>
  </div>
  <div id="advanced-options">
   <div class="row clear">
    <p class="label grid_6 alpha i18n" msg="option_label_stroke_timeout">Stroke Timeout (Milliseconds)</p>
    <p class="field grid_10">
     <input id="timeout" type="text" size="6" maxlength="6"/>
     <em><sub class="i18n" msg="option_desc_stroke_timeout">Large values make it easier to perform strokes</sub></em>
    </p>

    <p class="label grid_8 omega">
     <input id="enable_animation" type="checkbox"/>
     <label for="enable_animation" class="i18n" msg="option_label_enable_animation">Enable animations (scroll animations etc.)</label>
    </p>
   </div>

   <div class="row clear">
    <p class="label grid_6 alpha i18n" msg="option_label_minimal_step">Minimal Step (Pixels)</p>
    <p class="field grid_18 omega">
     <input id="minstep" type="text" size="6" maxlength="6"/>
    </p>
   </div>
  </div>
 </div>
</div>

<div id="built-in-strokes" class="grid_12"></div>

<div class="grid_12">
 <div id="windows-exclusive">
  <p class="title i18n" msg="category_label_rocker_strokes">Rocker Strokes</p>
  <div id="rocker-strokes" class="fold-group">
   <div class="row clear">
    <p class="label grid_4 alpha i18n" msg="stroke_label_rocker_right_to_left">Left click while holding the right button</p>
    <p class="field grid_8 omega"><select id="rockers-L"></select></p>
   </div>

   <div class="row clear">
    <p class="label grid_4 alpha i18n" msg="stroke_label_rocker_left_to_right">Right click while holding the left button</p>
    <p class="field grid_8 omega"><select id="rockers-R"></select></p>
   </div>
  </div>

  <p class="title">
   <span class="i18n" msg="category_label_wheel_strokes">Mouse Wheel Strokes</span>
   (<span class="i18n" msg="category_desc_wheel_strokes">Scroll while holding the right button</span>)
  </p>
  <div id="wheel-strokes" class="fold-group">
   <div class="row clear">
    <p class="label grid_4 alpha i18n" msg="stroke_label_wheel_up">Mouse wheel up</p>
    <p class="field grid_8 omega"><select id="wheels-U"></select></p>
   </div>

   <div class="row clear">
    <p class="label grid_4 alpha i18n" msg="stroke_label_wheel_down">Mouse wheel down</p>
    <p class="field grid_8 omega"><select id="wheels-D"></select></p>
   </div>

   <div class="row clear">
    <p class="label grid_4 alpha i18n" msg="stroke_label_wheel_left">Mouse wheel left</p>
    <p class="field grid_8 omega"><select id="wheels-L"></select></p>
   </div>

   <div class="row clear">
    <p class="label grid_4 alpha i18n" msg="stroke_label_wheel_right">Mouse wheel right</p>
    <p class="field grid_8 omega"><select id="wheels-R"></select></p>
   </div>
  </div>
 </div>

 <p class="title">
  <span class="i18n" msg="category_label_dnd_strokes">Drag'n'Drop Strokes</span>
  (<span class="i18n" msg="category_desc_dnd_strokes">Selected text, links and images can be dragged</span>)
 </p>
 <div id="drag-strokes" class="fold-group">
  <div class="row clear">
   <p class="label grid_4 alpha i18n" msg="stroke_label_dnd_up">Drop up</p>
   <p class="field grid_8 omega"><select id="drags-U"></select></p>
  </div>

  <div class="row clear">
   <p class="label grid_4 alpha i18n" msg="stroke_label_dnd_down">Drop down</p>
   <p class="field grid_8 omega"><select id="drags-D"></select></p>
  </div>

  <div class="row clear">
   <p class="label grid_4 alpha i18n" msg="stroke_label_dnd_left">Drop left</p>
   <p class="field grid_8 omega"><select id="drags-L"></select></p>
  </div>

  <div class="row clear">
   <p class="label grid_4 alpha i18n" msg="stroke_label_dnd_right">Drop right</p>
   <p class="field grid_8 omega"><select id="drags-R"></select></p>
  </div>

  <p class="note i18n" msg="text_dnd_notes">
   Dragging text will search the selected text in a new tab.<br/>
   The last drag direction counts.
  </p>
 </div>

 <p class="title">
  <span class="i18n" msg="category_label_custom_strokes">Custom Strokes</span> &mdash;
  <a id="add-custom-btn" href="javascript:void(0)" class="new-custom-stroke i18n" msg="caption_create_custom_stroke">Create</a> |
  <a href="http://ganq.net/mouse-stroke/custom-stroke/recently-added" class="share-custom-stroke i18n" msg="caption_share_custom_stroke">Share</a><sup class="new">new</sup> |
  <a href="http://ganq.net/mouse-stroke/page/custom-stroke-howto" class="i18n" msg="caption_help_custom_stroke">Help</a>
 </p>
 <div id="custom-strokes" class="fold-group"></div>
</div>

<div class="submit grid_24">
 <button id="bot-restore-btn" class="i18n" msg="caption_restore_default">Restore to default</button>
 <button id="bot-save-btn" class="i18n" msg="caption_save">Save</button>
</div>

<div id="footer" class="footer grid_24">
 <hr/>

 <p class="i18n" msg="text_extension_description">
  This is a Google Chrome extension which enables
  <a href="http://en.wikipedia.org/wiki/Mouse_gesture">mouse strokes</a>
  (also known as mouse gestures) in the browser. With this extension, you can
  perform common tasks by simply moving your mouse.
 </p>

 <div id="ookong" class="ookong">
  <iframe src="http://ookong.com/guanyin/index.php?tag=vigacmoe" frameborder="0" height="120" width="960"></iframe>
 </div>

 <p class="nav">
  <span class="credits">Icon designed by <a href="http://cuzmich.daportfolio.com/">cuzmichmail</a></span>
  <span class="credits">
   <span class="i18n" msg="caption_translated_by"></span>
   <span class="i18n" msg="text_translator"></span>
  </span>

  <a href="http://ganq.net/mouse-stroke">Home</a><sup class="new">new</sup> |
  <a href="http://code.google.com/p/chrome-mouse-stroke/issues/list">Support</a> |
  <a href="http://ganq.net/mouse-stroke/page/mouse-stroke-faqs">FAQs</a> |
  <a href="http://code.google.com/p/chrome-mouse-stroke/wiki/">Wiki</a> |
  <a class="donation" href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=6TGRFWXQ8V9LS">Donate</a><!-- |
  <a href="https://chrome.google.com/extensions/detail/aeaoofnhgocdbnbeljkmbjdmhbcokfdb">Google's extension gallery</a> |
  <a href="http://code.google.com/p/chrome-mouse-stroke/issues/detail?id=85" style="color:red;font-weight:bold">Translate this extension</a-->
 </p>
</div>

</body>
</html>
